#include <stdio.h>
#include <math.h>

//#define FADE_CUBIC_TYPE /*cubic root type*/
#define FADE_QUINTIC_TYPE /*quintic root type*/

#if defined FADE_CUBIC_TYPE

/**
 * [create fade out buffer]
 * @Author zcx
 * @Date   2023-02-28
 * @param  b             [volume start value ]
 * @param  c             [from start volume to end volumn difference]
 * @param  d             [fade out total time]
 * @param  samplerate	 [sound sample rate]
 * @param  fade_out_coff [fade out value buffer, size must be @d*@samplerate]
 * @note	for example: I need 160ms time do fade out, @samplerate is 48000Hz, 
 *       				volume from 1.0 to 0, so @b is 1.0, @c is -1.0, @t from 0 to 160*48000/1000 change,
 *       				@d is 160*48000/1000, @fade_out_coff size equal 160*48000/1000.
 */
void fade_out(float b, float c, float d, float samplerate, float *fade_out_coff)
{
	if(!fade_out_coff)
		return;
	// calculate total points
	int pts = (int)(d*samplerate/1000.0);
	// every point time
	float t = 0 ;
	for (int i = 0; i < pts; ++i)
	{
		t = 1.0*i/pts - 1;
   		fade_out_coff[i] = c*(t*t*t+1) + b;
	}
}
/**
 * [create fade in buffer]
 * @Author zcx
 * @Date   2023-02-28
 * @param  b             [volume start value ]
 * @param  c             [from start volume to end volumn difference]
 * @param  d             [fade in total time]
 * @param  samplerate    [sound sample rate]
 * @param  fade_in_coff  [fade in value buffer, size must be @d*@samplerate]
 * @note	for example: I need 160ms time do fade in, @samplerate is 48000Hz, 
 *       				volume from 0 to 1.0, so @b is 0, @c is 1.0, @t from 0 to 160*48000/1000 change,
 *       				@d is 160*48000/1000, @fade_out_coff size equal 160*48000/1000.
 */
void fade_in(float b, float c, float d, float samplerate, float *fade_in_coff)
{
	if(!fade_in_coff)
		return;
	// calculate total points
	int pts = (int)(d*samplerate/1000.0);
	// every point time
	float t = 0 ;
	for (int i = 0; i < pts; ++i)
	{
		t = 1.0*i/pts;
   		fade_in_coff[i] = c*t*t*t + b;
	}
}

#elif defined FADE_QUINTIC_TYPE

/**
 * [fade_process description]
 * @Author zcx
 * @Date   2023-08-23
 * @param  start_volumn             [volume start value ]
 * @param  stop_volumn             	[volumn stop value]
 * @param  fade_time             	[fade out total time ms]
 * @param  samplerate	 			[sound sample rate]
 * @param  fade_coff     			[fade out value buffer, size must be @fade_time*@samplerate]
 * @return              			[-1:input array memory error, -2: volumn set error, 0:no error]
 * @note	for example: I need 160ms time do fade out, @samplerate is 48000Hz, 
 *       				volume from 1.0 to 0, so @start_volumn is 1.0, @stop_volumn is 0, @t from 0 to 160*48000/1000 change,
 *       				@fade_time is 160*48000/1000, @fade_out_coff size equal 160*48000/1000.
 */
int fade_process(float start_volumn, float stop_volumn, float fade_time, float samplerate, float *fade_coff)
{
	if(!fade_coff)
		return -1;
	if(start_volumn < 0 || stop_volumn < 0 || fabs(start_volumn - stop_volumn) < 1e-6)
	{
		return -2;
	}

	// calculate total points
	int pts = (int)(fade_time*samplerate/1000.0);
	// every point time
	float t = 0 ;

	if(start_volumn > stop_volumn)
	{
		//fade out 
		//(start_volumn-stop_volumn).*(1.0-(6.*t.^5-15.*t.^4+10.*t.^3))+stop_volumn;
		for (int i = 0; i < pts; ++i)
		{
			t = 1.0*i/pts ;
			fade_coff[i] = (start_volumn-stop_volumn) *(1.0 - (6 * t * t * t * t * t - 15 * t * t * t * t + 10 * t * t * t)) + stop_volumn;
		}
	}
	else
	{
		//fade in
		//(stop_volumn-start_volumn).*(6.*t.^5-15.*t.^4+10.*t.^3)+start_volumn;
		for (int i = 0; i < pts; ++i)
		{
			t = 1.0*i/pts;
	   		fade_coff[i] = (stop_volumn - start_volumn)  * (6 * t * t * t * t * t - 15 * t * t * t * t + 10 * t * t * t) + start_volumn;
		}
	}
	return 0;
}

#endif



int main(int argc, char const *argv[])
{
	//get fade in buffer, 160*48000/1000=7680
	float fade_in_buffer[7680] = {0};
	fade_process(0.2, 0.5, 160, 48000, fade_in_buffer);
	printf("fade_in_buffer:\n");
	for (int i = 0; i < 7680; ++i)
	{
		printf("%.6f ", fade_in_buffer[i]);
	}
	printf("\n");

	//get fade out buffer, 160*48000/1000=7680
	float fade_out_buffer[7680] = {0};
	fade_process(0.8, 0.4, 160, 48000, fade_out_buffer);

	printf("fade_out_buffer:\n");
	for (int i = 0; i < 7680; ++i)
	{
		printf("%.6f ", fade_out_buffer[i]);
	}
	printf("\n");
	
	getchar();
	return 0;
}